package bid

import (
	"errors"
	"strconv"
	"wx-api/adx-bid/cache"
	"wx-api/adx-bid/model/m_adxapp"
	"wx-api/adx-bid/model/m_adxlist"
	"wx-api/adx-bid/model/m_adxplan"
	"wx-api/adx-bid/model/m_adxslot"
	"wx-api/adx-bid/model/m_channellist"
	"wx-api/adx-bid/model/m_channelslot"
	"wx-api/adx-bid/models/bid/BidModel"
)

type BudgetService struct {
	Req      *BidModel.BidRequest
	ResBid   *BidModel.BidResponse_SeatBid_Bid
	Adx      *m_adxlist.AdxList
	Media    *m_adxapp.AdxApp
	Slot     *m_adxslot.AdxSlot
	Plan     *m_adxplan.AdxPlan
	PlanItem *m_adxplan.ItemList
	Dsp      *m_channellist.ChannelList
	Pos      *m_channelslot.ChannelSlot
	Err      error
	Syst     string
	//价格
	IsRtb   bool    //是否竞价
	IsBid   bool    //竞价是否成功
	MdPrice float32 //媒体底价
	MFPrice float32 //媒体成交价
	MSPrice float32 //媒体发送给上游出价
	DdPrice float32 //上游出价
	DFPrice float32 //上游成交价
	SLRate  string  //曝光和点击是否控量
}

func DspBudget(sty string, p *BudgetService) {
	d := GetBudgetReq(p.Dsp.Uqid)
	if d == nil {
		p.Err = errors.New("dsp init error:" + p.Dsp.Code)
		return
	}
	//qps限制
	if d.IsQps {
		if !d.RateLime.Allow() {
			p.Err = errors.New("dsp req qps limit:" + p.Dsp.Uqid)
			return
		}
	}
	//广告位控量
	slot_limit, slot_err, s_ext := new(BudgetSlotLimit).CkBudgetSlotLimit(p.Pos)
	if !slot_limit {
		p.Err = errors.New("dsp slot limit:" + p.Pos.Uqid + "=" + slot_err.Error())
		return
	}
	p.SLRate = s_ext
	//单设备请求频次限制
	derr := new(BudgetReqLimit).IsLimit(p.Pos, p.Req.GetDevice())
	if derr != nil {
		p.Err = errors.New("IsLimit:" + derr.Error())
		return
	}
	//请求参数封装
	data, hd, surl, method, tms, err := GetBudgetNewObjFast(p)
	if err != nil {
		p.Err = err
		return
	}
	if method == "GET" {
		surl += "?" + string(data)
	}
	//上游请求日志记录
	go DspReqMsg(sty, p)
	robj := Req_fasthttp_new(p.Dsp.Code, method, surl, data, hd, d.IsJson, d.IsZip, tms)
	if robj.StatusCode == 999 {
		p.Err = errors.New("dsp req StatusCode:999")
		return
	}
	if robj.Error != nil {
		p.Err = robj.Error
		return
	}
	if robj.StatusCode != 200 && robj.StatusCode != 204 {
		p.Err = errors.New("dsp req StatusCode:" + strconv.Itoa(robj.StatusCode))
		return
	}
	if len(robj.Data) == 0 {
		p.Err = errors.New("dsp res DataLen:0")
		return
	}
	//设备频次记录
	go new(BudgetReqLimit).SetRedisDid(p.Pos, p.Req.GetDevice())
	//返回内容解析
	bidResp, err := DecBudgetNewObjFast(p, robj)
	if err != nil {
		p.Err = err
		return
	}
	if bidResp == nil {
		p.Err = errors.New("bidResp is nil")
		return
	}
	if len(bidResp.GetImgs()) == 0 && bidResp.GetVideo() == nil {
		p.Err = errors.New("dsp返回数据为空或者无可用素材")
		return
	}
	//上游返回日志记录
	go DspResMsg(sty, p)
	//返回数据统一处理
	err = doBidRes(bidResp, p)
	if err != nil {
		p.Err = errors.New("doBidRes error:" + err.Error())
		return
	}
	p.ResBid = bidResp
	return
}

func doBidRes(bid *BidModel.BidResponse_SeatBid_Bid, p *BudgetService) error {
	if p.Slot.TemplateId != "" { //返回模版id设置
		temp_info, ok := cache.CacheAdxTemplateMapGet(p.Slot.TemplateId)
		if ok {
			bid.StyleId = temp_info.CreateTemplateId
		}
	}
	if bid.GetDownUrl() != "" {
		bid.Clicktype = "3"
	}
	if bid.GetDpurl() != "" {
		bid.Clicktype = "2"
	}
	adtype := int32(1) //图片
	if bid.GetAdType() == 0 {
		if bid.GetTitle() != "" {
			adtype = 6
		}
		if bid.GetVideo() != nil {
			adtype = 2
		}
		if len(bid.GetImgs()) == 0 && bid.GetVideo() == nil && bid.GetTitle() != "" {
			adtype = 7
		}
		bid.AdType = adtype
	}
	//价格处理
	tprice := bid.GetPrice()
	//位置设置对底价
	if float32(p.Pos.LimitPrice) > 0 && float32(p.Pos.LimitPrice) > tprice {
		return errors.New("bid price is limit")
	}
	if p.IsRtb && tprice > 0 { //rtb竞价
		if p.PlanItem.MediaPrice > 0 { //固价
			p.MFPrice = float32(p.PlanItem.MediaPrice)
			p.IsBid = true
			p.DdPrice = tprice //上游出价
			p.DFPrice = tprice
		} else { //自动出价
			p.MFPrice, p.DFPrice, p.IsBid = PpriceV2(p.MdPrice, p.MFPrice, tprice, int64(p.PlanItem.MinPriceRate), int64(p.PlanItem.RetPriceRate), int64(p.Dsp.Rate))
		}
	} else {
		p.DdPrice = tprice //上游出价
		p.MFPrice = tprice //媒体成交价
		p.DFPrice = tprice //上游成交价
	}
	return nil
}
